/*
 * Copyright (c) 2007 jMouse Gestures
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMouse Gestures' nor the names of its contributors 
 *   may be used to endorse or promote products derived from this software 
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.jmg.mouse;

import com.jmg.space.Location;


/**
 * MouseMovement class records the movement of the mouse between any two
 * points.
 * <p>
 * This class is completely immutable and all property values must be set at
 * construction time.
 * </p>
 *
 * @author  Christopher Martin
 * @version $Id: MouseMovement.java 13 2007-05-24 12:13:13Z GentlemanHal $
 */
public class MouseMovement {   
    private float length;
    private float angle;
    
    
    
    
    
    /**
     * Creates a new instance of <code>MouseMovement</code>.
     * 
     * @param start The location the mouse started at.
     * @param end The location the mouse finished at.
     * @see   com.jmg.gesture.GestureMovement
     */
    public MouseMovement(Location start, Location end) {
        this(start.getX(), start.getY(), end.getX(), end.getY());
    }
    
    /**
     * Creates a new instance of <code>MouseMovement</code>.
     *
     * @param x1 The start x coordinate.
     * @param y1 The start y coordinate.
     * @param x2 The end x coordinate.
     * @param y2 The end y coordinate.
     * @see   com.jmg.gesture.GestureMovement
     */
    public MouseMovement(float x1, float y1, float x2, float y2) {
        float x = x2 - x1;
        float y = y2 - y1;
        
        length = (float) Math.hypot(x, y);
        angle  = (float) Math.atan2(y, x);
    }
    
    /**
     * Creates a new instance of <code>MouseMovement</code>.
     *
     * @param  length The length of movement.
     * @param  angle The angle of movement in radians.  If this angle is not
     *         in the range of {@link java.lang.Math#PI -pi} <= angle <=
     *         {@link java.lang.Math#PI pi} then it is automatically converted
     *         into that range.
     * @throws java.lang.IllegalArgumentException If length is less than zero.
     * @see    java.lang.Math#toRadians
     */
    public MouseMovement(float length, float angle) 
        throws IllegalArgumentException
    {
        if (length < 0f) {
            throw new IllegalArgumentException("length must be >= 0: " + length);
        }
        
        
        this.length = length;
        this.angle  = angle < (float) -Math.PI || angle > (float) Math.PI 
                ? angle % (float) Math.PI 
                : angle;
    }
    
    
    
    
    
    /**
     * Returns the length moved, will always be greater than or equal to zero.
     * 
     * @return The length.
     */
    public float getLength() {
        return length;
    }
    
    /**
     * Returns the angle in radians between {@link java.lang.Math#PI -pi} and
     * {@link java.lang.Math#PI pi}.
     * 
     * @return The angle.
     */
    public float getAngle() {
        return angle;
    }

    
    
    
    
    /**
     * Indicates whether some other object is "equal to" this one.
     * 
     * @param  obj The reference object with which to compare.
     * @return <code>true</code> if this object is the same as the obj
     *         argument; <code>false</code> otherwise.
     * @see    #hashCode()
     * @see    java.util.Hashtable
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        
        if (null == obj || obj.getClass() != getClass()) {
            return false;
        }
            
        MouseMovement mm = (MouseMovement) obj;

        return (mm.angle == angle && mm.length == length);
    }

    /**
     * Returns a hash code value for the object. This method is 
     * supported for the benefit of hash tables such as those provided by 
     * <code>java.util.Hashtable</code>.
     * 
     * @return A hash code value for this object.
     * @see    java.lang.Object#equals(java.lang.Object)
     * @see    java.util.Hashtable
     */
    @Override
    public int hashCode() {
        return Float.floatToIntBits(angle)  * 13 + 
               Float.floatToIntBits(length) * 13;
    }

    /**
     * Returns a string representation of the object.
     * 
     * @return a string representation of the object.
     */
    @Override
    public String toString() {
        StringBuilder buf = new StringBuilder();
        
        buf.append(getClass().getName());
        buf.append("[length=").append(length);
        buf.append(",angle=").append(angle);
        buf.append(']');
        
        return buf.toString();
    }
    
}
